home *** CD-ROM | disk | FTP | other *** search
/ Amiga Tools 4 / Amiga Tools 4.iso / tools / protect-your-privacy / p.g.p. / stealthpgp / stealth.c < prev    next >
C/C++ Source or Header  |  1996-02-26  |  19KB  |  688 lines

  1.  
  2. /*
  3.  * Stealth V1.0 by Henry Hastur
  4.  *
  5.  * May or may not be covered by US ITAR encryption export regulations, if
  6.  * in doubt, don't export it. It would be pretty stupid if it was, but
  7.  * hey, governments have done some pretty stupid things before now....
  8.  *
  9.  * This program is copyright Henry Hastur 1994, but may be freely distributed,
  10.  * modified, incorporated into other programs and used, as long as the
  11.  * copyright stays attached and you obey any relevant import or export
  12.  * restrictions on the code. No warranty is offered, and no responsibility
  13.  * is taken for any damage use of this program may cause. In other words,
  14.  * do what you want with it, but don't expect me to pay up if anything
  15.  * unexpected goes wrong - you're using it at your own risk...
  16.  *
  17.  */
  18.  
  19. #include <stdio.h>
  20. #include <ctype.h>
  21. #include <stdlib.h>
  22. #include <string.h>
  23. #include <unistd.h>
  24. #include <signal.h>
  25.  
  26. #ifdef __SASC
  27. #undef getc
  28. #undef putchar
  29. #endif
  30.  
  31. /* Few definitions from PGP for it's header/algorithm versions */
  32.  
  33. #define CURRENT_VERSION         0x02
  34. #define RSA_VERSION             0x01
  35. #define ID_SIZE                 8
  36.  
  37. /* define TRUE and FALSE */
  38.  
  39. #define TRUE    1
  40. #define FALSE   0
  41.  
  42. /* A byte */
  43.  
  44. #ifndef __SASC
  45. typedef unsigned char   byte;
  46. #endif
  47.  
  48. /* Few global variables */
  49.  
  50. static  int     verbose = FALSE;
  51. static  int     conventional = FALSE;
  52. static  int     adding = FALSE;
  53. static  char    file_name [1024];
  54. static  int     file_open = FALSE;
  55. static  FILE    *afp;
  56.  
  57. /* int_handler() - tidy up and exit */
  58.  
  59. static  void    int_handler(int unused)
  60. {
  61.         long    fpos;
  62.         int     c;
  63.  
  64.         /* If we've still got a file open */
  65.  
  66.         if (file_open) {
  67.  
  68.                 /* If we can still write to it, erase it */
  69.  
  70.                 if (afp) {
  71.                         fseek (afp, 0l, 2);
  72.                         fpos = ftell (afp);
  73.                         fseek (afp, 0l, 0);
  74.  
  75.                         while (fpos --)
  76.                                 putc (0, afp);
  77.                 }
  78.  
  79. #ifndef UNIX
  80.                 /* Finally unlink it */
  81.  
  82.                 unlink (file_name);
  83. #endif
  84.         }
  85.  
  86.         exit (1);
  87. }
  88.  
  89. /* Read a PGP ctb-lengh */
  90.  
  91. static  long    read_length (int c,
  92.                              FILE *fp)
  93. {
  94.         static  int     bytes [] = { 1, 2, 4, 0 };
  95.         long    len = 0;
  96.         int     n;
  97.  
  98.         n = bytes [c & 0x03];
  99.  
  100.         if (!n)
  101.                 return 0x7FFFFFFF;
  102.  
  103.         for (; n > 0 ; n--) {
  104.                 len *= 256;
  105.                 len += getc(fp);
  106.         }
  107.  
  108.         return len;
  109. }
  110.  
  111. /* Write a PGP ctb-length */
  112.  
  113. static  void    write_length (int ctb,
  114.                               unsigned long length,
  115.                               FILE *fp)
  116. {
  117.         unsigned long   mask;
  118.         int     bytes, shift,c;
  119.  
  120.         ctb &= 0xFC;
  121.  
  122.         if (length < 256) {
  123.                 mask = 0xFF;
  124.                 bytes = 1;
  125.                 shift = 0;
  126.         }
  127.         else if (length < 65536) {
  128.                 mask = 0xFF00;
  129.                 bytes = 2;
  130.                 shift = 8;
  131.                 ctb |= 1;
  132.         }
  133.         else {
  134.                 mask = 0xFF000000;
  135.                 shift = 24;
  136.                 bytes = 4;
  137.                 ctb |= 2;
  138.         }
  139.  
  140.         putc (ctb, fp);
  141.  
  142.         while (bytes-- > 0) {
  143.                 c = ((length & mask) >> shift);
  144.                 mask >>= 8;
  145.                 shift -= 8;
  146.  
  147.                 putc (c, fp);
  148.         }
  149. }
  150.  
  151. /* Hunt through pubring.pgp for the appropriate secret key */
  152.  
  153. #define ID_FROM_NAME    0
  154. #define LENGTH_FROM_ID  1
  155.  
  156. static  int     find_key_id(byte *id,
  157.                             int *length,
  158.                             char *s,
  159.                             int type)
  160. {
  161.         char    *path;
  162.         char    pub_name [1024];
  163.         FILE    *pub = NULL;
  164.         int     c1, c2, len, i, klen, c;
  165.         char    userid [256];
  166.  
  167.         /* Find pubring.pgp */
  168.  
  169.         if (path = getenv("PGPPATH")) {
  170.                 sprintf (pub_name, "%s/pubring.pgp", path);
  171.                 pub = fopen(pub_name, "rb");
  172.         }
  173.  
  174.         if (!pub)
  175.                 pub = fopen ("pubring.pgp", "rb");
  176.  
  177.         if (!pub) {
  178.                 fprintf (stderr,"Can't find pubring.pgp in $PGPPATH or . : exiting !\n");
  179.                 exit (1);
  180.         }
  181.  
  182.         /* Read the contents till we find what we're looking for */
  183.  
  184.         while ((c1 = getc(pub)) != EOF) {
  185.                 c2 = (c1 & 0xBC);
  186.  
  187.                 switch (c2) {
  188.  
  189.                         /* Secret key, probably revocation cert.  */
  190.  
  191.                         case 0x94:
  192.                         len = read_length (c1, pub);
  193.  
  194.                         for (; len > 0; len--)
  195.                                  (void) getc (pub);
  196.  
  197.                         break;
  198.  
  199.                         /* Public key - grab id and length */
  200.  
  201.                         case 0x98:
  202.                         len = read_length (c1, pub);
  203.  
  204.                         for (i = 0; i < 8; i++)
  205.                                 (void) getc (pub);
  206.  
  207.                         len -= 10;
  208.  
  209.                         /* OK, here we are at the public modulus, get the
  210.                            size from the MPI header */
  211.  
  212.                         klen = getc(pub) * 256;
  213.                         klen += getc (pub);
  214.  
  215.                         /* Return the length for the caller to use */
  216.  
  217.                         *length = klen;
  218.  
  219.                         /* We only need the last 64 bits */
  220.  
  221.                         len -= ((klen + 7) / 8);
  222.                         i = (((klen + 7) / 8) - ID_SIZE);
  223.  
  224.                         /* Skip unneccesary bytes */
  225.  
  226.                         for (; i > 0; i--) {
  227.                                 (void) getc (pub);
  228.                         }
  229.  
  230.                         if (type == ID_FROM_NAME) {
  231.                                 for (i = 0; i < ID_SIZE; i++) {
  232.                                         id [i] = getc(pub);
  233.                                 }
  234.                         }
  235.                         else {
  236.  
  237.                                 /* Looking for length from ID */
  238.  
  239.                                 int     found_id = TRUE;
  240.  
  241.                                 for (i = 0; i < ID_SIZE; i++) {
  242.                                         if (id[i] != getc(pub))
  243.                                                 found_id = FALSE;
  244.                                 }
  245.  
  246.                                 if (found_id) {
  247.                                         fclose (pub);
  248.                                         return TRUE;
  249.                                 }
  250.                         }
  251.  
  252.                         for (; len > 0 ; len--) {
  253.                                 (void) getc (pub);
  254.                         }
  255.  
  256.                         break;
  257.  
  258.                         /* Keyring trust, comment */
  259.  
  260.                         case 0xB0:
  261.                         case 0xB8:
  262.  
  263.                         len = getc (pub);
  264.  
  265.                         for (; len > 0; len--)
  266.                                 (void) getc (pub);
  267.  
  268.                         break;
  269.  
  270.                         /* USER ID ! */
  271.  
  272.                         case 0xB4:
  273.  
  274.                         len = getc (pub);
  275.  
  276.                         if (type == ID_FROM_NAME) {
  277.                                 for (i = 0; i < len; i++) {
  278.                                         c = getc (pub);
  279.                                         userid [i] = tolower (c);
  280.                                 }
  281.  
  282.                                 userid [i] = 0;
  283.  
  284.                                 if (strstr(userid, s)) {
  285.                                         if (verbose)
  286.                                                 fprintf (stderr, "Found user: %s\n",userid);
  287.                                         return TRUE;
  288.                                 }
  289.                         }
  290.                         else
  291.                                 for (i = 0; i < len; i++)
  292.                                         (void) getc (pub);
  293.                         break;
  294.  
  295.                         /* Anything we don't care about */
  296.  
  297.                         default:
  298.                         len = read_length (c1, pub);
  299.  
  300.                         for (; len > 0; len--)
  301.                                 (void) getc (pub);
  302.                         break;
  303.  
  304.                 }
  305.         }
  306.  
  307.         fclose (pub);
  308.  
  309.         /* Uh-oh, failed to find it ! */
  310.  
  311.         return FALSE;
  312. }
  313.  
  314. /* Strip_headers() : Should be obvious what this does, really ! */
  315.  
  316. static  void    strip_headers(FILE *fp)
  317. {
  318.         int     c1,c2;
  319.         long    len;
  320.         int     i;
  321.         byte    id [ID_SIZE];
  322.         int     key_length;
  323.         byte    key_length_found = FALSE;
  324.         byte    rsa_written = FALSE;
  325.         int     mpi_length;
  326.  
  327.         /* Run through the whole message checking each packet */
  328.  
  329.         while ((c1 = getc(fp)) != EOF) {
  330.                 c2 = (c1 & 0xBC);
  331.  
  332.                 switch (c2) {
  333.  
  334.                         /* Public key encoded packet */
  335.  
  336.                         case 0x84:
  337.  
  338.                         /* Read length */
  339.  
  340.                         len = read_length(c1, fp);
  341.                         if (verbose)
  342.                                 fprintf (stderr, "Found %d byte RSA packet.\n",
  343.                                         len);
  344.  
  345.                         /*
  346.                            We only support ONE RSA block ! This is because
  347.                            we have no idea of the file format when we start
  348.                            adding headers, so we have to assume that this
  349.                            is the case. Warn the user, then abort...
  350.                         */
  351.  
  352.                         if (rsa_written) {
  353.                                 fprintf (stderr, "WARNING: More than one RSA block found... stripping extra block !\n");
  354.  
  355.                                 /* Throw away the block */
  356.  
  357. ohno_abort_abort:
  358.                                 while (len-- > 0)
  359.                                         (void) getc (fp);
  360.  
  361.                                 break;
  362.                         }
  363.  
  364.                         /* Check for conventional encryption specified */
  365.  
  366.                         if (conventional) {
  367.                                 fprintf (stderr, "WARNING: You specified conventional encryption with an RSA-encrypted file !\nI hope you know what you're doing... stripping RSA header....\n");
  368.  
  369.                                 goto ohno_abort_abort;
  370.                         }
  371.  
  372.                         /* Check public key version byte */
  373.  
  374.                         c1 = getc (fp);
  375.  
  376.                         if (c1 != CURRENT_VERSION) {
  377.                                 fprintf(stderr, "Hmm, PK version %d not %d, may not decrypt at recipient\n", c1, CURRENT_VERSION);
  378.                         }
  379.  
  380.                         /* Strip key ID */
  381.  
  382.                         for (i = 0; i < ID_SIZE; i++)
  383.                                 id[i] =  getc (fp);
  384.  
  385.                         if (find_key_id (id,&key_length,NULL,LENGTH_FROM_ID)) {
  386.                                 key_length_found = TRUE;
  387.                         }
  388.  
  389.                         /* Check RSA version byte */
  390.  
  391.                         c1 = getc(fp);
  392.  
  393.                         if (c1 != RSA_VERSION) {
  394.                                 fprintf (stderr, "Hmm, RSA version %d not %d, may not decrypt at recipient\n", c1, RSA_VERSION);
  395.                         }
  396.  
  397.                         /* Strip MPI prefix */
  398.  
  399.                         mpi_length = getc(fp);
  400.                         mpi_length = mpi_length * 256 + getc(fp);
  401.  
  402.                         /* Now, we have a problem in that PGP may generate
  403.                            an RSA block shorter than your key, in which
  404.                            case decryption is likely to fail. Check for
  405.                            this and warn the user ! */
  406.  
  407.                         if (!key_length_found) {
  408.                                 fprintf (stderr, "Hmm, couldn't get the length of this key, so can't verify that decryption\nwill be successful.\n");
  409.                         }
  410.                         else {
  411.                                 if (((mpi_length + 7) / 8) !=
  412.                                         ((key_length + 7) / 8)) {
  413.                                         fprintf (stderr, "WARNING : Short RSA block output, decryption will probably fail if used !\n");
  414.                                 }
  415.                         }
  416.  
  417.                         /* Copy remaining data from packet */
  418.  
  419.                         len -= 12;
  420.                         for (; len > 0; len--)
  421.                                 putchar (getc(fp));
  422.  
  423.                         rsa_written = TRUE;
  424.                         break;
  425.  
  426.                         /* IDEA packet */
  427.  
  428.                         case 0xA4:
  429.  
  430.                         /* Read length */
  431.  
  432.                         len = read_length(c1, fp);
  433.                         if (verbose)
  434.                                 fprintf (stderr, "Found %d byte IDEA packet.\n",
  435.                                         len);
  436.  
  437.                         /* Copy data from packet */
  438.  
  439.                         for (; len > 0; len--)
  440.                                 putchar (getc (fp));
  441.  
  442.                         break;
  443.  
  444.                         default:
  445.  
  446.                         /* Oh no ! Don't know what this is - just skip it ! */
  447.  
  448.                         if (verbose)
  449.                                 fprintf (stderr, "Oops ! Unexpected packet type, skipping !\n");
  450.  
  451.                         len = read_length (c1, fp);
  452.  
  453.                         for (; len > 0; len --)
  454.                                 (void) getc (fp);
  455.  
  456.                         break;
  457.                 }
  458.         }
  459. }
  460.  
  461. /* Now we put the headers back in again */
  462.  
  463. static  void    add_headers(byte *id,
  464.                             int length)
  465. {
  466.         unsigned long   len, mask;
  467.         int     shift;
  468.         int     i, c;
  469.         long    fpos;
  470.         long    flen;
  471.         int     s;
  472. #ifdef USE_PGPPATH
  473.         char    *pgp_path;
  474. #endif
  475.  
  476.         /* Foo ! We have to use a temporary file, because we need to be
  477.            able to output the length after reading it in ! */
  478.  
  479. #ifdef USE_TMP
  480.         strcpy (file_name, "/tmp/stealth.t");
  481. #else
  482. #ifdef USE_PGPPATH
  483.         pgp_path = getenv ("PGPPATH");
  484.  
  485.         if (!pgp_path) {
  486.                 fprintf (stderr, "PGPPATH not set !\n");
  487.                 exit (1);
  488.         }
  489.  
  490.         sprintf(file_name,"%s/stealth.t",pgp_path);
  491. #else
  492.         strcpy (file_name, "stealth.t");
  493. #endif
  494. #endif
  495.  
  496.         s = strlen (file_name);
  497.  
  498.         i = 0;
  499.         while (!access (file_name, F_OK) && i < 100) {
  500.                 sprintf (file_name + s, "%d", i++);
  501.         }
  502.  
  503.         afp = fopen (file_name,"w+b");
  504.  
  505.         if (!afp) {
  506.                 fprintf (stderr, "Can't open '%s' !\n", file_name);
  507.                 exit (2);
  508.         }
  509.  
  510.         /* On unix, unlink the file immediately, to improve security */
  511.  
  512. #ifdef UNIX
  513.         unlink (file_name);
  514. #endif
  515.  
  516.         file_open = TRUE;
  517.  
  518.         if (!conventional) {
  519.  
  520.                 /* First output the PK header */
  521.  
  522.                 len = 4 + ID_SIZE + (length + 7)/8;
  523.  
  524.                 write_length (0x84, len, afp);
  525.                 putc (CURRENT_VERSION, afp);
  526.  
  527.                 /* Store the key ID */
  528.  
  529.                 for (i = 0; i < 8; i++) {
  530.                         putc (id [i], afp);
  531.                 }
  532.  
  533.                 /* RSA version */
  534.  
  535.                 putc (RSA_VERSION, afp);
  536.  
  537.                 /* MPI header */
  538.  
  539.                 c = (length & 0xFF00) >> 8;
  540.                 putc (c, afp);
  541.                 putc (length & 0xFF, afp);
  542.  
  543.                 /* Copy the MPI over */
  544.  
  545.                 i = (length + 7) / 8;
  546.                 while (i-- > 0) {
  547.                         c = getchar();
  548.                         putc (c, afp);
  549.                 }
  550.  
  551.         }
  552.  
  553.         /* Now the IDEA bits */
  554.  
  555.         len = 0xFFFFFFFF;
  556.  
  557.         fpos = ftell (afp) + 1;
  558.         write_length (0xA4, len, afp);
  559.  
  560.         len = 0;
  561.  
  562.         while ((c = getchar ()) != EOF) {
  563.                 len ++;
  564.                 putc (c, afp);
  565.         }
  566.  
  567.         fseek (afp, fpos, 0);
  568.  
  569.         /* Set up mask for length writing */
  570.  
  571.         mask = 0xFF000000;
  572.         shift = 24;
  573.  
  574.         /* Write the length back */
  575.  
  576.         for (i = 0; i < 4; i++) {
  577.                 c = (len & mask) >> shift;
  578.                 shift -= 8;
  579.                 mask >>= 8;
  580.  
  581.                 putc (c, afp);
  582.         }
  583.  
  584.         /* OK, now let's output the data ! */
  585.  
  586.         fseek (afp, 0l, 0);
  587.  
  588.         while ((c = getc (afp)) != EOF) {
  589.                 putchar (c);
  590.         }
  591.  
  592.         /* Erase the file */
  593.  
  594.         flen = ftell (afp);
  595.  
  596.         fseek (afp, 0l,0);
  597.  
  598.         while (flen --)
  599.                 putc (0, afp);
  600.  
  601.         fclose (afp);
  602.         afp = NULL;
  603.  
  604. #ifndef UNIX
  605.         /* Finally, delete the temporary file */
  606.  
  607.         unlink (file_name);
  608. #endif
  609.  
  610.         file_open = FALSE;
  611. }
  612.  
  613. static  char    looking_for [256];
  614.  
  615. /* Do the stuff */
  616.  
  617. main(int argc,
  618.      char *argv[])
  619. {
  620.         int     length;
  621.         byte    id [ID_SIZE];
  622.         char    *s, *d;
  623.         int     arg = 1,i;
  624.  
  625.         /* Set the umask for any files we may create */
  626.  
  627. #ifdef UNIX
  628.         umask (077);
  629. #endif
  630.  
  631.         signal (SIGINT, int_handler);
  632.  
  633.         /* Check command line parameters */
  634.  
  635.         while (arg != argc && argv [arg][0] == '-') {
  636.  
  637.                 for (i = 1; argv[arg][i]; i++) {
  638.                         switch (argv[arg][i]) {
  639.  
  640.                                 case 'v':
  641.                                 verbose = TRUE;
  642.                                 break;
  643.  
  644.                                 case 'c':
  645.                                 conventional = TRUE;
  646.                                 break;
  647.  
  648.                                 case 'a':
  649.                                 adding = TRUE;
  650.                                 break;
  651.  
  652.                         }
  653.                 }
  654.  
  655.                 arg++;
  656.         }
  657.  
  658.         if (!adding)
  659.                 strip_headers (stdin);
  660.         else {
  661.                 if (!conventional) {
  662.  
  663.                         if (arg == argc) {
  664.                                 fprintf (stderr, "You specified -a, but gave no user id !\n");
  665.                                 exit (1);
  666.                         }
  667.  
  668.                         s = argv[arg];
  669.                         d = looking_for;
  670.  
  671.                         while (*s) {
  672.                                 *d++ = tolower (*s);
  673.                                 s++;
  674.                         }
  675.                         *d = 0;
  676.                 }
  677.  
  678.                 if (conventional ||
  679.                         find_key_id (id,&length,looking_for,ID_FROM_NAME)) {
  680.                         add_headers (id, length);
  681.                 }
  682.                 else {
  683.                         fprintf (stderr, "Can't find key for user %s\n",argv[arg]);
  684.                 }
  685.         }
  686. }
  687.  
  688.